#include "watchpoint.h"
#include "expr.h"

#define NR_WP 32

static WP wp_pool[NR_WP];
static WP *head, *free_;

void init_wp_pool()
{
	int i;
	for (i = 0; i < NR_WP; i++)
	{
		wp_pool[i].NO = i;
		wp_pool[i].next = &wp_pool[i + 1];
	}
	wp_pool[NR_WP - 1].next = NULL;

	head = NULL;
	free_ = wp_pool;
}

/* TODO: Implement the functionality of watchpoint */

WP *new_wp()
{
	WP *p1;
	p1 = free_;
	free_ = free_->next;
	p1->next = NULL;

	if (head == NULL)
	{
		head = p1;
		head->next = NULL;
	}
	else if (head->next == NULL)
	{
		head->next = p1;
		p1->next = NULL;
	}
	else
	{
		WP *f, *q;
		f = head;
		while (f->next != NULL && f->NO < p1->NO)
		{
			q = f;
			f = f->next;
		}

		if (f->next == NULL && f->NO < p1->NO)
		{
			f->next = p1;
		}
		else
		{
			p1->next = f;
			q->next = p1;
		}
	}
	// WP *tb;
	// tb = head;
	// while(tb != NULL){
	// 	printf("%d ", tb->NO);
	// 	tb = tb->next;
	// }
	// printf("\n");
	return p1;
}

void free_wp(WP *wp)
{
	WP *pp; // target watchpoint
	if (head == NULL)
	{
		Assert(head == NULL, "The watchpoint list is empty\n");
	}
	else if (head->NO == wp->NO)
	{
		pp = head;
		head = head->next;
		pp->next = NULL;
	}
	else
	{
		// printf("here\n");
		WP *p1, *p2;
		p1 = head;
		while (p1->next != NULL && p1->NO != wp->NO)
		{
			p2 = p1;
			p1 = p1->next;
		}
		if (p1->NO == wp->NO)
		{
			pp = p1;
			p2->next = p1->next;
			pp->next = NULL;
		}
	}

	if (free_ == NULL)
	{
		free_ = pp;
	}
	else
	{
		// printf("here2\n");
		WP *f;
		f = free_;
		while (f->next != NULL)
		{
			f = f->next;
		}
		f->next = pp;
	}

	// WP *tb;
	// tb = free_;
	// while(tb != NULL){
	// 	printf("%d ", tb->NO);
	// 	tb = tb->next;
	// }
	// printf("\n");
}

void delete_wp(int num)
{
	WP *f;
	f = &wp_pool[num];
	free_wp(f);
}

bool check_wp()
{
	WP *p;
	p = head;
	bool key = true;
	bool success;
	while (p != NULL)
	{
		uint32_t current_val = expr(p->expr, &success);
		if (current_val != p->val)
		{
			key = false;
			printf("Watchpoint %d\t%s\n", p->NO, p->expr);
			printf("Old value %d\t\n", p->val);
			printf("New value %d\t\n", current_val);
			p->val = current_val;
		}
		p = p->next;
	}
	return key;
}

void display_watchpoint()
{
	WP *p;
	p = head;
	if (p == NULL)
	{
		printf("Watchpoint is empty now\n");
	}
	else
	{
		while (p != NULL)
		{
			printf("Watchpoint No.%d\t%s\n", p->NO, p->expr);
			p = p->next;
		}
	}
}